/*
 * File:   CommandManager.cpp
 * Author: Gab'z
 * 
 * Created on 27 mai 2012, 20:14
 */

#include "CommandManager.h"
#include "../model/command/UndoableRedoableCommand.h"
#include "../model/memento/MementoCaretaker.h"
#include "Engine.h"
#include "model/command/literal/Expression.h"


namespace calculator {
    Logger* CommandManager::log = LoggerManager::getInstance()->getLogger("CommandManager");

    CommandManager::CommandManager(Engine * const engine, MementoCaretaker * const mementoCaretaker) :
    _engine(engine),
    _mementoCaretaker(mementoCaretaker) {
    }

    CommandManager::~CommandManager() {
    }
    
    std::string CommandManager::getPreviousInputString() const {
        return _mementoCaretaker->getPreviousInputString();
    }

    std::string CommandManager::executeCommand(const Command* command) throw (CommandException) {
        log->trace("Executing command " + command->toString() + "...");

        std::string result = command->isExecutable();
        log->debug("Result TEST isExecutable command : " + command->toString() + " is : " + result);
        if (!result.empty()) {
            std::ostringstream oss;
            oss << "Command " << command->toString() << " aborted : " << result;
            log->debug(oss.str());
            return result;
        } else {
            const UndoableRedoableCommand* undoableRedoableCommand = dynamic_cast<const UndoableRedoableCommand*> (command);
            // On prépare une sauvegarde si la commande est annulable
            const Memento* memento;
            if (undoableRedoableCommand != 0) {
                log->trace("Command is Undoable :");
                
                try {
                    memento = undoableRedoableCommand->createMemento();
                    log->debug("Memento created");
                } catch (CommandException& e) {
                    // Memento non crée
                    log->error("Error while creating Memento");
                    std::ostringstream oss;
                    oss << "Executing command " << command->toString() << " aborted";
                    log->error(oss.str());
                    throw;
                }
                /**
                 * 
                 * on ne sauvegardera le memento que si 
                 * la commande s'est executée correctement
                 */
                log->debug("executeCommand : Memento in cache");
            }

            try {
                command->execute();
            } catch (CommandException& e) {
                // comportement particulier pour les erreurs pendant l'exécution des expressions
                // le memento est alors conservé
                // on récupère le contenu de la ligne à afficher à partir de l'exception
                const Expression* exp = dynamic_cast<const Expression*> (command);
                if (exp != 0) {
                    std::string str = e.what();
                    return str;
                } else if (undoableRedoableCommand != 0) {
                    // Commmande non executée mais memento déjà placé en mémoire
                    // si UndoRedoCommand et non expression il faut supprimer son memento
                    delete memento;
                    log->debug("executeCommand : Rollback : _tmpMemento deleted");
                    std::ostringstream oss;
                    oss << "Executing command " << command->toString() << " aborted";
                    log->error(oss.str());
                    return e.what();
                }

            }
            /**
             * 
             * sauvegarde du memento
             * si UndoRedoCommand
             */
            if (undoableRedoableCommand != 0) {
               _mementoCaretaker->addMemento(memento);
                log->debug("AddMemento : committed");
            }
        }
        log->trace("Executing command " + command->toString() + " done");
        return "";
    }
}
